<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  
  <title>双能卫</title>
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
  <meta name="description">
<meta property="og:type" content="website">
<meta property="og:title" content="双能卫">
<meta property="og:url" content="http://www.libcz.com/blog/index.html">
<meta property="og:site_name" content="双能卫">
<meta property="og:description">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="双能卫">
<meta name="twitter:description">
  
    <link rel="alternative" href="/blog/atom.xml" title="双能卫" type="application/atom+xml">
  
  
    <link rel="icon" href="http://images.libcz.com:8000/images/favicon.png">
  
  <link rel="stylesheet" href="/blog/css/style.css" type="text/css">
</head>
<body>
  <div id="container">
    <div class="left-col">
    <div class="overlay"></div>
<div class="intrude-less">
	<header id="header" class="inner">
		<a href="/" class="profilepic">
			
			<img lazy-src="http://images.libcz.com:8000/images/white_bg_logo.png" class="js-avatar">
			
		</a>

		<hgroup>
		  <h1 class="header-author"><a href="/">C Z</a></h1>
		</hgroup>

		
		<p class="header-subtitle">双能卫</p>
		

		
			<div class="switch-btn">
				<div class="icon">
					<div class="icon-ctn">
						<div class="icon-wrap icon-house" data-idx="0">
							<div class="birdhouse"></div>
							<div class="birdhouse_holes"></div>
						</div>
						<div class="icon-wrap icon-ribbon hide" data-idx="1">
							<div class="ribbon"></div>
						</div>
						
						
					</div>
					
				</div>
				<div class="tips-box hide">
					<div class="tips-arrow"></div>
					<ul class="tips-inner">
						<li>菜单</li>
						<li>标签</li>
						
						
					</ul>
				</div>
			</div>
		

		<div class="switch-area">
			<div class="switch-wrap">
				<section class="switch-part switch-part1">
					<nav class="header-menu">
						<ul>
						
							<li><a href="/blog">主页</a></li>
				        
							<li><a href="/blog/archives">所有文章</a></li>
				        
						</ul>
					</nav>
					<nav class="header-nav">
						<div class="social">
							
								<a class="github" target="_blank" href="http://github.com/cz-it" title="github">github</a>
					        
						</div>
					</nav>
				</section>
				
				
				<section class="switch-part switch-part2">
					<div class="widget tagcloud" id="js-tagcloud">
						<a href="/blog/tags/backend-vmstat/" style="font-size: 10px;">backend vmstat</a> <a href="/blog/tags/golang-cli/" style="font-size: 10px;">golang cli</a> <a href="/blog/tags/navigation/" style="font-size: 10px;">navigation</a> <a href="/blog/tags/swift/" style="font-size: 10px;">swift</a> <a href="/blog/tags/tabbar/" style="font-size: 10px;">tabbar</a>
					</div>
				</section>
				
				
				

				
			</div>
		</div>
	</header>				
</div>
    </div>
    <div class="mid-col">
      <nav id="mobile-nav">
  	<div class="overlay">
  		<div class="slider-trigger"></div>
  		<h1 class="header-author js-mobile-header hide">C Z</h1>
  	</div>
	<div class="intrude-less">
		<header id="header" class="inner">
			<div class="profilepic">
				<img lazy-src="http://images.libcz.com:8000/images/white_bg_logo.png" class="js-avatar">
			</div>
			<hgroup>
			  <h1 class="header-author">C Z</h1>
			</hgroup>
			
			<p class="header-subtitle">双能卫</p>
			
			<nav class="header-menu">
				<ul>
				
					<li><a href="/blog">主页</a></li>
		        
					<li><a href="/blog/archives">所有文章</a></li>
		        
		        <div class="clearfix"></div>
				</ul>
			</nav>
			<nav class="header-nav">
				<div class="social">
					
						<a class="github" target="_blank" href="http://github.com/cz-it" title="github">github</a>
			        
				</div>
			</nav>
		</header>				
	</div>
</nav>
      <div class="body-wrap">
  
    <article id="post-iOS/后台程序员学习swift开发app/TabBar/创建另一张TabBar大众脸的app" class="article article-type-post" itemscope itemprop="blogPost">
  
    <div class="article-meta">
      <a href="/blog/2015/05/17/iOS/后台程序员学习swift开发app/TabBar/创建另一张TabBar大众脸的app/" class="article-date">
  	<time datetime="2015-05-16T16:00:00.000Z" itemprop="datePublished">2015-05-17</time>
</a>
    </div>
  
  <div class="article-inner">
    
      <input type="hidden" class="isFancy" />
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="/blog/2015/05/17/iOS/后台程序员学习swift开发app/TabBar/创建另一张TabBar大众脸的app/">另一张TabBar大众脸的App</a>
    </h1>
  

      </header>
      
    
    <div class="article-entry" itemprop="articleBody">
      
        <p>前面我们通过Navigation创建了一种可以切换界面外壳的App，其实拿起iPhone，我们发现除了这种类型还有另一种类型外壳的App.如下图：</p>
<p><img src="http://images.libcz.com:8000/images/blog/iOS/后台程序员学习swift开发app/TabBar/alarm.png" alt="alarm"> <img src="http://images.libcz.com:8000/images/blog/iOS/后台程序员学习swift开发app/TabBar/appstore.png" alt="appstore"></p>
<p>我们发现这类App都是在最下面有一排Tab，每个Tab的Item表示一个分类的界面，通过点击这些Tab可以切换到对应的界面中。再回想下QQ/微信、<br>淘宝/天猫、微博等每天都要用的App。</p>
<p>发现了什么？？？这些App都是这样的一个基本外壳。是不是把这个学会了，就是做牛逼哄哄的App了？</p>
<h2 id="一、TabBar是神马">一、TabBar是神马</h2><p>在Developer上的文章<a href="https://developer.apple.com/library/ios/documentation/WindowsViews/Conceptual/ViewControllerCatalog/Chapters/TabBarControllers.html#//apple_ref/doc/uid/TP40011313-CH3-SW1" target="_blank" rel="external">《View Controller Catalog for iOS》</a> 中对TabBar的定义为：</p>
<blockquote>
<p> It is composed of views that the tab bar controller manages directly and views that are managed by content view controllers you provide. Each content view controller manages a distinct view hierarchy, and the tab bar controller coordinates the navigation between the view hierarchies.</p>
</blockquote>
<p>说白了就是一个管理其他用于承载实际内容的ViewController的容器ViewController,并且可以通过TabBar进行UI上的导航，也就是上面我们举例App的操作效果。</p>
<p>我们来看下其组成结构图：</p>
<p><img src="http://images.libcz.com:8000/images/blog/iOS/后台程序员学习swift开发app/TabBar/tabbar_struct.png" alt="tabbar_struct"></p>
<p>主要就是由下面的一个TabBar的list和承载显示内容的TabBarControllerView组成，每个TabBar还可以设置一个小的标题title和一个图标。<br>并且每个图标上面还可以显示一个红点（想想微信里面有新消息的时候）来表示一些提示信息。因此我们可以猜想，其实现就是用一个数组来保存每个<br>界面的ViewController，然后绘制一个可触发的Tab，当点击的时候切换到对应的ViewController中。 这样我们再看官方的分解图就容易理解了:</p>
<p><img src="http://images.libcz.com:8000/images/blog/iOS/后台程序员学习swift开发app/TabBar/tabbar_struct1.png" alt="tabbar_struct1"></p>
<h2 id="二、通过Tab切换界面">二、通过Tab切换界面</h2><p>这里我手写一个界面：</p>
<p><img src="http://images.libcz.com:8000/images/blog/iOS/后台程序员学习swift开发app/TabBar/appdelegate.png" alt="appdelegate"></p>
<p>这里创建一个 <code>UITabBarController</code>对象<code>rootVC</code>作为window的rootviewcontroller。如果就这样的话（打开这里的return 的注释），那么我们可以看到运行结果中就是在下面有个tab站位区间的界面。</p>
<p><img src="http://images.libcz.com:8000/images/blog/iOS/后台程序员学习swift开发app/TabBar/empty_tab.png" alt="empty_tab"></p>
<p>这时我们再创建几个容器ViewController，并为其创建一个一个带有背景颜色的View，从而方便鉴别。最后将这些容器ViewController赋给上面我们说的数组中：</p>
<pre><code>root<span class="title">VC.viewControllers = [tabVC01</span>,tab<span class="title">VC02</span>,tab<span class="title">VC03</span>,tab<span class="title">VC04</span>,tab<span class="title">VC05</span>,tab<span class="title">VC06</span>,]
</code></pre><p>可以看到我们的运行效果：</p>
<p><img src="http://images.libcz.com:8000/images/blog/iOS/后台程序员学习swift开发app/TabBar/tabbar_run.png" alt="tabbar_run"></p>
<h2 id="三、设置单个界面">三、设置单个界面</h2><p>在上面的代码中，我们除了设置了每个容器ViewController的view属性，从而展示界面效果，同时还为其设置了tabBarItem属性，该属性就是上面Tab占位区域中的元素。其主要由一个小图标的Icon和一个提示文字组成。对应类：UITabBarItem 。我们看下其构造函数：</p>
<pre><code><span class="function"><span class="title">init</span><span class="params">(title: String?, image: UIImage?, tag: Int)</span></span>
@<span class="function"><span class="title">availability</span><span class="params">(iOS, introduced=<span class="number">7.0</span>)</span></span>
<span class="function"><span class="title">init</span><span class="params">(title: String?, image: UIImage?, selectedImage: UIImage?)</span></span>
<span class="function"><span class="title">init</span><span class="params">(tabBarSystemItem systemItem: UITabBarSystemItem, tag: Int)</span></span>
</code></pre><p>构造函数里面传入一个title和一个UIImage对象对应上面说的图标Icon和提示文字。在iOS7.0之后还可以设置一个选中状态时的图标。上面的演示中，直接利用XCode的特性，用named属性初始化一个UIImage对象：</p>
<pre><code>let barAddItemImg = <span class="function"><span class="title">UIImage</span><span class="params">(named: <span class="string">"barbuttonicon_add"</span>)</span></span>
</code></pre><p>然后用这个UIImage对象和一个title构造一个UITabBarItem:</p>
<pre><code>tabVC01<span class="class">.tabBarItem</span> = <span class="function"><span class="title">UITabBarItem</span><span class="params">(title: <span class="string">"One"</span>, image: barAddItemImg, tag: <span class="number">1</span>)</span></span>
</code></pre><p>在构造完每个子界面的容器ViewController的UITabBarItem后，就可以将其装入UITabBarController中了：</p>
<pre><code>root<span class="title">VC.viewControllers = [tabVC01</span>,tab<span class="title">VC02</span>,tab<span class="title">VC03</span>,tab<span class="title">VC04</span>,tab<span class="title">VC05</span>,tab<span class="title">VC06</span>,]
</code></pre><p>诚如上面的推测，这里直接将要控制的ViewController构成一个数组放置在rootVC中。</p>
<p>这里，强势的iOS又有一个潜在的规则，Tab上的元素最多不能超过5个（含），多于5个的部分，会将第5个之后的元素全部替换成一个More的UITabBarItem并且其Icon也生成好了。当点击这个“More”的时候，会出现一个TableView的列表将剩余的容器ViewController依次列出来：</p>
<p><img src="http://images.libcz.com:8000/images/blog/iOS/后台程序员学习swift开发app/TabBar/more.png" alt="more"></p>
<p>这里iOS还自动生成了一个Edit的菜单，点击后用户可以修改TabBarItem的顺序，当然，这一切都是不用我们手动写代码，而是UITabBarController自身带有的功能。</p>
<p>这里我们看到“More”的Title和图标以及点进去后的“Edit”都是自动生成的，那是否可以对这些值进行自定义呢？UITabBarController抛出一个属性让我们可以访问到这个“More”ViewController，也就是：“moreNavigationController” 。从命名中我们就可以看出其是一个NavigationController，那就好办了，翻翻我们前面的一篇文章就知道怎么用这个ViewController。这里我们重新为其生成一个tabBarItem就可以替换在UITabBarController的Tab占位区域中的“More”的Tab了。通过获得moreNavigationController的栈顶的ViewController，遍可以设置其内容中的Title和“Edit”按钮，分别对应到<code>moreNavigationController.topViewController!.navigationItem.title</code>和<code>moreNavigationController.topViewController!.navigationItem.rightBarButtonItem?</code> ，看下代码：</p>
<pre><code><span class="function_or_atom">rootVC</span>.<span class="function_or_atom">moreNavigationController</span>.<span class="function_or_atom">tabBarItem</span> = <span class="variable">UITabBarItem</span>(<span class="function_or_atom">title</span>: <span class="string">"更多"</span>, <span class="function_or_atom">image</span>: <span class="function_or_atom">barAddItemImg</span>, <span class="function_or_atom">tag</span>: <span class="number">7</span>)

<span class="function_or_atom">rootVC</span>.<span class="function_or_atom">moreNavigationController</span>.<span class="function_or_atom">tabBarItem</span>.<span class="function_or_atom">title</span> = <span class="string">"更多"</span>
<span class="function_or_atom">rootVC</span>.<span class="function_or_atom">moreNavigationController</span>.<span class="function_or_atom">topViewController</span><span class="exclamation_mark">!</span>.<span class="function_or_atom">navigationItem</span>.<span class="function_or_atom">title</span> = <span class="string">"更多"</span>
<span class="function_or_atom">rootVC</span>.<span class="function_or_atom">moreNavigationController</span>.<span class="function_or_atom">topViewController</span><span class="exclamation_mark">!</span>.<span class="function_or_atom">navigationItem</span>.<span class="function_or_atom">rightBarButtonItem</span>?.<span class="function_or_atom">title</span> = <span class="string">"编辑"</span>
</code></pre><p>这里就实现了提示的自定义：</p>
<p><img src="http://images.libcz.com:8000/images/blog/iOS/后台程序员学习swift开发app/TabBar/more_cus.png" alt="more_cus"></p>
<h2 id="四、中间发生了神马">四、中间发生了神马</h2><p>在这些点击跳转的过程中，我们是否可以加一些控制呢？比如让某个tab不生效？答案是肯定的，这时UITabBarController抛出了一个delegate来作这样的事情：UITabBarControllerDelegate</p>
<p>其主要代理了如下几个过程：</p>
<pre><code><span class="variable">@availability</span>(iOS, introduced=<span class="number">3.0</span>)
optional func <span class="function">tabBarController</span>(<span class="attribute">tabBarController</span>: UITabBarController, shouldSelectViewController <span class="attribute">viewController</span>: UIViewController) -&gt; Bool
optional func <span class="function">tabBarController</span>(<span class="attribute">tabBarController</span>: UITabBarController, didSelectViewController <span class="attribute">viewController</span>: UIViewController)

<span class="variable">@availability</span>(iOS, introduced=<span class="number">3.0</span>)
optional func <span class="function">tabBarController</span>(<span class="attribute">tabBarController</span>: UITabBarController, willBeginCustomizingViewControllers <span class="attribute">viewControllers</span>: [AnyObject])
<span class="variable">@availability</span>(iOS, introduced=<span class="number">3.0</span>)
optional func <span class="function">tabBarController</span>(<span class="attribute">tabBarController</span>: UITabBarController, willEndCustomizingViewControllers <span class="attribute">viewControllers</span>: [AnyObject], <span class="attribute">changed</span>: Bool)
optional func <span class="function">tabBarController</span>(<span class="attribute">tabBarController</span>: UITabBarController, didEndCustomizingViewControllers <span class="attribute">viewControllers</span>: [AnyObject], <span class="attribute">changed</span>: Bool)

<span class="variable">@availability</span>(iOS, introduced=<span class="number">7.0</span>)
optional func <span class="function">tabBarControllerSupportedInterfaceOrientations</span>(<span class="attribute">tabBarController</span>: UITabBarController) -&gt; Int
<span class="variable">@availability</span>(iOS, introduced=<span class="number">7.0</span>)
optional func <span class="function">tabBarControllerPreferredInterfaceOrientationForPresentation</span>(<span class="attribute">tabBarController</span>: UITabBarController) -&gt; UIInterfaceOrientation

<span class="variable">@availability</span>(iOS, introduced=<span class="number">7.0</span>)
optional func <span class="function">tabBarController</span>(<span class="attribute">tabBarController</span>: UITabBarController, interactionControllerForAnimationController <span class="attribute">animationController</span>: UIViewControllerAnimatedTransitioning) -&gt; UIViewControllerInteractiveTransitioning?

<span class="variable">@availability</span>(iOS, introduced=<span class="number">7.0</span>)
optional func <span class="function">tabBarController</span>(<span class="attribute">tabBarController</span>: UITabBarController, animationControllerForTransitionFromViewController <span class="attribute">fromVC</span>: UIViewController, toViewController <span class="attribute">toVC</span>: UIViewController) -&gt; UIViewControllerAnimatedTransitioning?
</code></pre><p>每个回调的用途翻阅Developer的<a href="https://developer.apple.com/library/ios/documentation/UIKit/Reference/UITabBarControllerDelegate_Protocol/index.html#//apple_ref/occ/intfm/UITabBarControllerDelegate/tabBarController:didSelectViewController:" target="_blank" rel="external">手册</a>即可。最常用的就是前面两个。</p>
<ul>
<li><ul>
<li>tabBarController:shouldSelectViewController: // 是否设置选中</li>
</ul>
</li>
</ul>
<p>这个回调在点击某个tab的时候被调用，此时还没有进行切换，通过控制其返回false，可以使得不发生跳转，也就是点击无效的结果。</p>
<ul>
<li><ul>
<li>tabBarController:didSelectViewController:</li>
</ul>
</li>
</ul>
<p>当点击完tab完成切换后被调用。这个比较常用如，点击后做一些统计操作，或者一些初始化操作。</p>

      
    </div>
    
    <div class="article-info article-info-index">
      
      
	<div class="article-tag tagcloud">
		<ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/blog/tags/tabbar/">tabbar</a></li></ul>
	</div>

      
	<div class="article-category tagcloud">
	<a class="article-category-link" href="/blog/categories/iOS/">iOS</a>
	</div>


      
      <div class="clearfix"></div>
    </div>
    
  </div>
  
</article>







  
    <article id="post-backend/vmstat_初体验" class="article article-type-post" itemscope itemprop="blogPost">
  
    <div class="article-meta">
      <a href="/blog/2015/05/15/backend/vmstat_初体验/" class="article-date">
  	<time datetime="2015-05-14T16:00:00.000Z" itemprop="datePublished">2015-05-15</time>
</a>
    </div>
  
  <div class="article-inner">
    
      <input type="hidden" class="isFancy" />
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="/blog/2015/05/15/backend/vmstat_初体验/">VMStat 初体验</a>
    </h1>
  

      </header>
      
    
    <div class="article-entry" itemprop="articleBody">
      
        <p>当你的Windows连续开机一个星期时，你是不是发现机器特别慢，点啥啥不开。但是你去看资源管理器的又发现内存占用也没有到90%，CPU也没跑满。那为什么这个时候会那么卡呢？</p>
<p>其中一个原因就是由于长期使用机器且没有关机，导致内存中缓存了大量的数据。由于系统的虚拟内存管理，当内存使用达到一定程度时，系统会将内存中<br>的数据交换到硬盘中，也就是Windos的虚拟内存，在Linux中叫Swap分区。此时如果要使用交换到硬盘上的数据，那么系统首先要把内存中最远最久没有<br>使用的数据交换到硬盘，再把硬盘中需要的数据加载到内存，然后才可以跑逻辑，这样就造成了“点啥啥不开”的残像了。</p>
<p>那么这样的情况会不会发生在我们的Server端Linux上呢？答案当然是肯定的。而且一旦该情况发生，有可能产生雪崩效应，一下就把服务器弄回老家了。<br>这里的典型案例就有云风大大遇到的<a href="http://blog.codingnow.com/2014/03/mmzb_redis.html" target="_blank" rel="external">Redis转储</a>。又或者可以自己手写一个无限分配<br>内存并使用的例子。然后静静等待系统挂掉的那一刻。</p>
<p>那么什么时候会发生这样的情况？或者说当我们的系统表现出什么的症状时我们要考虑这样的情况？如何进行确诊？</p>
<p>一般当系统频繁的需要新内存时可能发生这样的情况，如频繁的读文件而不释放、网络接收大量文件写磁盘（写磁盘跟不上内存从网络接收的量）。此时我们的系统<br>对外相应速度会急剧下降但是CPU又没有跑满。这时我们就应该考虑是不是虚拟内存频繁交换的问题了。通过使用vmstat可以帮助我们来确诊是不是这个原因。</p>
<p>##1. vmstat输出<br>裸奔运行vmstat命令，可以看到一行输出。该行输出内容表示的自系统最近启动后虚拟内存和CPU的平均情况。<br>在输出的第一行我们称之为表头。依次包含了：</p>
<pre><code><span class="comment">procs</span> <span class="literal">-</span><span class="literal">-</span><span class="literal">-</span><span class="literal">-</span><span class="literal">-</span><span class="literal">-</span><span class="literal">-</span><span class="literal">-</span><span class="literal">-</span><span class="literal">-</span><span class="literal">-</span><span class="comment">memory</span><span class="literal">-</span><span class="literal">-</span><span class="literal">-</span><span class="literal">-</span><span class="literal">-</span><span class="literal">-</span><span class="literal">-</span><span class="literal">-</span><span class="literal">-</span><span class="literal">-</span> <span class="literal">-</span><span class="literal">-</span><span class="literal">-</span><span class="comment">swap</span><span class="literal">-</span><span class="literal">-</span> <span class="literal">-</span><span class="literal">-</span><span class="literal">-</span><span class="literal">-</span><span class="literal">-</span><span class="comment">io</span><span class="literal">-</span><span class="literal">-</span><span class="literal">-</span><span class="literal">-</span> <span class="literal">-</span><span class="literal">-</span><span class="comment">system</span><span class="literal">-</span><span class="literal">-</span> <span class="literal">-</span><span class="literal">-</span><span class="literal">-</span><span class="literal">-</span><span class="literal">-</span><span class="comment">cpu</span><span class="literal">-</span><span class="literal">-</span><span class="literal">-</span><span class="literal">-</span><span class="literal">-</span>
</code></pre><p>几个字段，第二行我们称之为子表头，依次包含了：</p>
<pre><code><span class="keyword">r</span>  <span class="keyword">b</span>   swpd   free   buff  cache   si   <span class="keyword">so</span>    bi    <span class="keyword">bo</span>   in   <span class="keyword">cs</span> us <span class="keyword">sy</span> id <span class="keyword">wa</span> <span class="keyword">st</span>
</code></pre><p>其意义分别为：</p>
<ol>
<li><p>procs : 使用内存IO的进程统计</p>
<ul>
<li>r : 获取了IO资源而等待cpu运行的进程数目</li>
<li>b :　因为等待ＩＯ资源而阻塞休眠的进程数目</li>
</ul>
</li>
<li><p>memory: 虚拟内存相关统计</p>
<ul>
<li>swpd : 用掉的虚拟内存大小。也就是交换分区内用掉的大小</li>
<li>free : 空闲的内存大小。</li>
<li>buff ： 被用作系统buffer的大小。比如write系统调用的时候，系统不会立马写磁盘，而是先缓冲到buffer中然后在合适的时候写入磁盘。</li>
<li>cache ： 被用作系统cache的大小。</li>
</ul>
</li>
</ol>
<p>这里，free的大小表示一定可以使用的大小，即malloc不会出错的大小。但是超过free时malloc会一定出错么？也不一定。因为系统的buff和cache在必要<br>的时候也会优先给malloc使用。只有在不可使用时才会出错，如被设置为共享内存。因此观察时要综合这四个位置一起作判断。当分配内存时首先使用free,free不够的时候从buff和cache中匀得，当还不够时选择从swap分区中取得。</p>
<ol>
<li><p>swap: 交换分区的使用情况</p>
<ul>
<li>si : 每秒从硬盘中交换到内存中的大小。</li>
<li>so ：每秒从内存中交换到硬盘中的大小。</li>
</ul>
</li>
<li><p>io :  块设备IO统计</p>
<ul>
<li>bi : 每秒从块设备读入内存的大小</li>
<li>bo ： 每秒从内存中写入快设备的大小</li>
</ul>
</li>
</ol>
<p>什么是块设备？Linux下的设备主要分成字符设备和块设备（可以参考LDD《linux device driver》），类似于Socket属于流设备，而磁盘一般属于块设备。因此这个参数可以用来衡量写磁盘的性能。</p>
<ol>
<li><p>system　: 操作系统中断和上下文切换统计</p>
<ul>
<li>in :　操作的系统每秒触发的中断数目</li>
<li>cs ： 操作系统每秒上下文切换次数，这里上下文切换可以认为是系统态到用户态或者反过来的切换</li>
</ul>
</li>
<li><p>cpu： cpu相关统计</p>
<ul>
<li>us : 用户态代码执行占用的cpu时间。</li>
<li>sy ：系统态代码执行占用的cpu时间。</li>
<li>id ： cpu空闲时间，也就是执行系统idle的时间，cpu是不可能停机的。</li>
<li>wa ： 耗费在等待IO上的时间</li>
<li>st ： 其他的等待时间。</li>
</ul>
</li>
</ol>
<p>##2. vmstat的使用</p>
<p>上面我们裸跑vmstat就可以得到一个输出，表示的是：自系统最近启动后虚拟内存和CPU的平均情况。</p>
<p>vmstat的调用格式为:</p>
<pre><code>vmstat <span class="command">delay</span> <span class="command">count</span> [options]
</code></pre><p>这里先介绍一个“-a”选项。<br>如果使用了 “-a” 选项，我们会发现其输出和上面描述的有点不一样。在memory的下面，没有了buff和cache子列了，取而代之的是inact和active子列。<br>他们分别表示激活的和非激活的内存大小。那怎样理解“激活”呢？对比增加了-a选和没有增加-a选项的结果我们可以发现inact + active = cache大小。<br>也就是我们上面讨论，如果系统中free的内存不够了，那么就去用cache和buff里面的内存。但是并不是都可以用的，其中可以用的就是inact部分。因此<br>我们可以知道，系统此时还可以使用的内存大小为 free+inact大小。如果该和持续下降，那么我们就要注意了。是不是有内存泄露、或者内存分配洪请求等<br>情况的出现了。</p>
<p>除此之外还有个”-d”选项<br>通过使用“-d”选项，可以仅查看写磁盘的性能。有一级表头 disk， reads， writes， IO四大块。disk表示的是分区名称。reads和writes分别表示<br>读写扇区数目。其中都有： total merged sectors  ms ：</p>
<ul>
<li>total   : 总共读取/写入成功的数目</li>
<li>merged  : 合在一起读取操作的数目</li>
<li>sectors ：读取/写入成功的扇区数目</li>
<li>ms      ：一次读或者写耗费的时间，单位是毫秒</li>
</ul>
<p>IO中包含了cur表示当前正在处理的IO数目，s表示每处理一个IO请求耗费的时间，单位是秒。<br>“-d”选项中包含了很多ram开头的随机分区。为了更清楚的查看可以使用<br>“-p”选项 指定某个分区。如 ：</p>
<pre><code>vmstat -dp <span class="regexp">/dev/</span>sda1
</code></pre><p>可以仅查看该分区硬盘的读写情况。</p>

      
    </div>
    
    <div class="article-info article-info-index">
      
      
	<div class="article-tag tagcloud">
		<ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/blog/tags/backend-vmstat/">backend vmstat</a></li></ul>
	</div>

      
	<div class="article-category tagcloud">
	<a class="article-category-link" href="/blog/categories/backend/">backend</a>
	</div>


      
      <div class="clearfix"></div>
    </div>
    
  </div>
  
</article>







  
    <article id="post-iOS/后台程序员学习swift开发app/Navigation/通过navigation创建一张大众脸的app" class="article article-type-post" itemscope itemprop="blogPost">
  
    <div class="article-meta">
      <a href="/blog/2015/05/11/iOS/后台程序员学习swift开发app/Navigation/通过navigation创建一张大众脸的app/" class="article-date">
  	<time datetime="2015-05-10T16:00:00.000Z" itemprop="datePublished">2015-05-11</time>
</a>
    </div>
  
  <div class="article-inner">
    
      <input type="hidden" class="isFancy" />
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="/blog/2015/05/11/iOS/后台程序员学习swift开发app/Navigation/通过navigation创建一张大众脸的app/">通过Navigation创建一张大众脸的App</a>
    </h1>
  

      </header>
      
    
    <div class="article-entry" itemprop="articleBody">
      
        <p>拿出iPhone。随手点开几个系统应用，比如“信息”，我们会看到如下的界面结构：</p>
<p><img src="http://images.libcz.com:8000/images/blog/iOS/后台程序员学习swift开发app/Navigation/message_01.png" alt="message_01"> <img src="http://images.libcz.com:8000/images/blog/iOS/后台程序员学习swift开发app/Navigation/message_02.png" alt="message_02"></p>
<p>或者点开“设置”也会发现他是有个首部的标题栏加上“Body”部分内容，然后再内容中点击后会跳转到子界面，并且在子界面中保留了首部，同时首部会有“返回”字样的按钮可以会<br>到上一层界面中。</p>
<p>这样的一个界面结构在App中比较常见，可谓是一张“大众脸”。</p>
<h2 id="二、Navigation是什么">二、Navigation是什么</h2><p>在Developer的文档中有这么一篇 <a href="https://developer.apple.com/library/ios/documentation/WindowsViews/Conceptual/ViewControllerCatalog/Introduction.html#//apple_ref/doc/uid/TP40011313-CH1-SW1" target="_blank" rel="external">《View Controller Catalog for iOS》</a><br>说是介绍iOS上ViewController分类的，但是真正的ViewController肯定远不止这几类，但是这里的几类确是最基本的几类，一般用来构成一个App最基础的骨架，所以才有了上面的那张“大众脸”，Navigation就是其中的一种。</p>
<blockquote>
<p>A navigation controller is an instance of the UINavigationController class that you use as-is in your app. Apps that contain structured content can use navigation controllers to navigate between levels of content. The navigation controller itself manages the display of one or more custom view controllers, each of which manages the data at a specific level in your data hierarchy. The navigation controller also provides controls for determining the current location in this data hierarchy and for navigating back up the hierarchy.</p>
</blockquote>
<p>这篇文章介绍说一个Navigation Controller 是一个容器ViewController，用来管理多个其他的承载显示View的View Controller，其最主要的功能就在于控制当前加载哪个View Controller并提供返回路径。Developer网站上的文档给了一个App的示意图来展示<br>Navigation在一个App中的物理存在：</p>
<p><img src="http://images.libcz.com:8000/images/blog/iOS/后台程序员学习swift开发app/Navigation/navigation.png" alt="navigation"></p>
<p>从图中可以看到上面定义中的“管理并加载当前的ViewController”已经“提供返回路径”。从Developer的文档中我们可以看到Navigation的组成如下：</p>
<p><img src="http://images.libcz.com:8000/images/blog/iOS/后台程序员学习swift开发app/Navigation/nav_struct.png" alt="nav_struct"></p>
<p>用一个数值存储这UIViewController，从而可以完成跳转操作，然后用UINavigationBar来定义界面的首部，从而提供返回按钮，toolBar定义了界面的尾部，提供一些自定义界面的可能。同时还通过delegate来监听事件的改变。</p>
<h2 id="三、在不同的项目界面中跳转">三、在不同的项目界面中跳转</h2><p>我们创建一个简单的工程测试一下这个“管理加载”和“返回路径”的功能。首先创建一个“Single View”的工程，但是我们这里不用storyboard,直接手写更能说明问题。根据前一篇文章<a href="">Swift App中的Main Loop</a>中描述的，其实我们只要”AppDelegate.swift”这一个文件就可以了。<br>我们修改这个文件：</p>
<p><img src="http://images.libcz.com:8000/images/blog/iOS/后台程序员学习swift开发app/Navigation/appdelegate.png" alt="appdelegate"></p>
<p>这里我们首先定义一个成员 <code>var navVC : UINavigationController?</code>，由于我们不在构造函数里面做初始化，所以将其定义为 “optional”变量，原因参见<a href="">Swift语法：继承中的构造函数</a>这篇文章。上面有说到，UINavigationController只是一个容器ViewController。其<br>并不能用来作为主界面的view的显示，所以需要为其设置一个rootViewController，这就和要为window设置一个rootViewController的原理类似。因此我们创建一个最简单的类似一个白板幕布一样的“UIViewController”对象。并在创建“UINavigationController”的时候再构造<br>函数里面进行设置。</p>
<p>因为需要进行内容的显示，这里我们用了一个容器View “UIView”，并创建了一个Button用来切换到下一个界面。这里有点注意的在iOS7以后，UIButtonType中已经没有圆角了，用System进行替代，如果要定义外观可以用图片。这里就是简单的创建一个UIView和一个UIButton，然后为button设置一个触发时候的动作，并将button用addSubview的方式加到容器View上面，再将容器View设置为UIViewController的view，就可以进行显示了。别忘了最后将UINavigationController设置成window的rootControllerView。这里运行时效果如下：</p>
<p><img src="http://images.libcz.com:8000/images/blog/iOS/后台程序员学习swift开发app/Navigation/jump_01.png" alt="jump_01"> <img src="http://images.libcz.com:8000/images/blog/iOS/后台程序员学习swift开发app/Navigation/jump_02.png" alt="jump_02"></p>
<p>这里Button的触发函数里面和前面一样，就是创建一个UIViewController和一个背景View，然后增加一个按钮，同时这个按钮的触发也再执行这个逻辑。这样就可以通过这个按钮无尽的往下去点了。点击“Back”可以回到上层ViewController。这新ViewController的加载是通过调用<br>“pushViewController”来实现的。虽然Navigation也提供了相对的”popViewController”的接口，但基本不需要使用。</p>
<h2 id="四、自定义界面的header">四、自定义界面的header</h2><p>但是我们在用“信息”、“设置”的时候发现，在节目的首部不仅有这个“Back”字眼的按钮，还有一些其他按钮，比如“信息”这个Title，比如写短信的图标等。那这些是怎么来的呢？Navigation其实自己还是可以进行一些内容显示的，并可以进行一些自定义。那些信息就显示在UINavigationController.navigationBar的区域内，具体由UINavigationController.navigationBar.navigationItem来表示。其结构如下：</p>
<p><img src="http://images.libcz.com:8000/images/blog/iOS/后台程序员学习swift开发app/Navigation/barbuttonitem.png" alt="barbuttonitem"></p>
<p>可以自定义的部分包括了三块，左边的“backBarButtonItem”/“leftBarButtonItem”。中间的title部分以及右边的“rightBarButtonItem”。</p>
<h3 id="左边的返回键/自定义键">左边的返回键/自定义键</h3><p>这三块地方中的左边有两种选择：要么是可以返回上级的“backBarButtonItem”，此时不要设置“leftBarButtonItem”否则会覆盖返回按钮。这里我们在回望下上面的图，会发现“backBarButtonItem”是属于上一个ViewController的，而其他两个是属于当前的ViewController。<br>这里初学者很容易混淆，比如我最开始就认为是在UINavigationController里面对这三个元素进行设置（ps:可恨的是它也有这三个属性，然后进行设置后总是不起效果），另一个比较容易出现的设置了子ViewController的backBarButtonItem，但是跳转后界面还是死活显示一个<br>“Back”。如果看了这个图我们就好理解了。在上面的例子中，我们为rootVC设置这个属性：</p>
<pre><code>rootVC<span class="variable">.navigationItem</span><span class="variable">.backBarButtonItem</span>  = <span class="built_in">UIBarButtonItem</span>()
rootVC<span class="variable">.navigationItem</span><span class="variable">.backBarButtonItem</span>?<span class="variable">.title</span> = <span class="string">"RootVC"</span>
</code></pre><p>这样我们点击跳转的时候就可以看到对应的变化了。注意，这里我们没有设置其action,因为对于backBarButtonItem的action就一个作用，即使设置了也不起效果</p>
<p><img src="http://images.libcz.com:8000/images/blog/iOS/后台程序员学习swift开发app/Navigation/back.png" alt="back"></p>
<p>如果不想要返回作用，我们也可以将其设置成自定义的。并且可以通过action设置其自定义动作。比如我们看oschina的客户端，其左上角的按钮就定义成了个人中心 </p>
<p><img src="http://images.libcz.com:8000/images/blog/iOS/后台程序员学习swift开发app/Navigation/oschina.png" alt="oschina"></p>
<p>这里注意是子ViewController的leftBarButtonItem。比如我们定义rootVC的leftBarButtonItem设置为书签并给SecondVC设置为系统的播放按钮：</p>
<pre><code>rootVC<span class="class">.navigationItem</span><span class="class">.leftBarButtonItem</span> = <span class="function"><span class="title">UIBarButtonItem</span><span class="params">(barButtonSystemItem: UIBarButtonSystemItem.Bookmarks, target: nil, action: Selector(<span class="string">"NextSection"</span>)</span></span>)
...
secnondVC<span class="class">.navigationItem</span><span class="class">.leftBarButtonItem</span>  = <span class="function"><span class="title">UIBarButtonItem</span><span class="params">(barButtonSystemItem: UIBarButtonSystemItem.Play, target: nil, action: Selector(<span class="string">"NextSection"</span>)</span></span>)
</code></pre><p>这个时候我们会发现首页就出现了rootVC上的书签，因为他是当前ViewController。并且当点击跳转下一个界面时，我们发现，之前设置的rootVC的“backBarButtonItem”不见了，被secondVC的leftBarButtonItem覆盖了。这里我们可以看出leftBarButtonItem的优先级是要高的：</p>
<p><img src="http://images.libcz.com:8000/images/blog/iOS/后台程序员学习swift开发app/Navigation/root_bookmark.png" alt="root_bookmark"> <img src="http://images.libcz.com:8000/images/blog/iOS/后台程序员学习swift开发app/Navigation/second_play.png" alt="second_play"></p>
<h3 id="中间的Title">中间的Title</h3><p>中间的部分最简单的就是如“信息”应用一样，设置一个标题。我们可以通过title属性进行设置：</p>
<pre><code>rootVC<span class="class">.navigationItem</span><span class="class">.title</span> = <span class="string">"RootVC"</span>
</code></pre><p>这样我们看到的首页就会变成 </p>
<p><img src="http://images.libcz.com:8000/images/blog/iOS/后台程序员学习swift开发app/Navigation/root_title.png" alt="root_title"></p>
<p>但是很多时候我们并不满足只设置一段文字，我们可能还想实现类似QQ那样的“段页面”，或者插入一个搜素框。</p>
<p>我们先来看怎么实现一个类似QQ的“段页面”</p>
<pre><code>let segmentedBar = <span class="function"><span class="title">UISegmentedControl</span><span class="params">(items: [<span class="string">"消息"</span>,<span class="string">"电话"</span>])</span></span>
rootVC<span class="class">.navigationItem</span><span class="class">.titleView</span> = segmentedBar
</code></pre><p>这里主要是定制navigationItem.titleView,其接受一个UIView对象。这里可以看出来一个UIView给了我们充分的自定义空间。比如上面我们增加了一个“段页面”,效果如下：</p>
<p><img src="http://images.libcz.com:8000/images/blog/iOS/后台程序员学习swift开发app/Navigation/root_seg.png" alt="root_seg"></p>
<p>类似的，我们还可以插入一个搜索框:</p>
<pre><code>let searchBar = <span class="function"><span class="title">UISearchBar</span><span class="params">()</span></span>
searchBar<span class="class">.barStyle</span> = UIBarStyle<span class="class">.BlackTranslucent</span>
rootVC<span class="class">.navigationItem</span><span class="class">.titleView</span> = searchBar
</code></pre><p>这里我们看到效果图中的搜索栏一下吧后面的空间全给占掉了。</p>
<p><img src="http://images.libcz.com:8000/images/blog/iOS/后台程序员学习swift开发app/Navigation/root_search.png" alt="root_search"></p>
<p>但是不要紧，既然是UIView，那么我们只要定义一个容器View，具体里面就随我们自由发挥了。</p>
<h3 id="右边的自定义键">右边的自定义键</h3><p>右边的自定义键实际上就是一个UIBarButtonItem。和上面的leftBarButtonItem一样，我们创建UIBarButtonItem即可。</p>
<h2 id="五、状态回调">五、状态回调</h2><p>在ViewController之间互相切换的时候，我们也是可以进行一些状态控制的。其通过UINavigationControllerDelegate定义了这些事件变化的接口：</p>
<p><img src="http://images.libcz.com:8000/images/blog/iOS/后台程序员学习swift开发app/Navigation/nav_event.png" alt="nav_event"></p>
<p>通过这个回调我们可以在ViewController消失和加载时加入一些自定义动作。</p>
<h2 id="六、灵活使用界面的footer">六、灵活使用界面的footer</h2><p>在最上面介绍Navigation的时候，还有一个toolbar的结构。正常情况下这个toolbar是不现实的。当我们将UINavigationController的toolbarHidden属性置为“false”就可以看到在底部会有一个类似首部navigationItem的效果了。在Developer的文档中我们也可以找到<br>一副说明的图例：</p>
<p><img src="http://images.libcz.com:8000/images/blog/iOS/后台程序员学习swift开发app/Navigation/nav_apple.png" alt="nav_apple"></p>
<p>这里我们添加一个搜索的toobaritem，看代码：</p>
<pre><code><span class="comment">// 首先打开rooVC的toolBar显示</span>
navVC?<span class="variable">.toolbarHidden</span> = <span class="literal">false</span>
let  searchToolbar = <span class="built_in">UIBarButtonItem</span>(barButtonSystemItem: <span class="built_in">UIBarButtonSystemItem</span><span class="variable">.Search</span>, target: <span class="literal">nil</span>, action: <span class="literal">nil</span>)
rootVC<span class="variable">.toolbarItems</span> = [searchToolbar]

<span class="comment">// 对于 SecondVC 关闭toolBar显示</span>
navVC?<span class="variable">.toolbarHidden</span> = <span class="literal">true</span>
</code></pre><p>这样我们就看到了在首页里面就有一个搜索按钮，当点击到下一个界面就看不到下面的这个toolbar了：</p>
<p><img src="http://images.libcz.com:8000/images/blog/iOS/后台程序员学习swift开发app/Navigation/root_toolbar_search.png" alt="root_toolbar_search"> </p>
<p>这里在代码中我们首先创建一个UIBarButtonItem，然后将其放在数组中赋给rooVC的toolbarItems成员，从而实现对toolbar的自定义，这里数组中的元素会依次显示在toolbar当中。</p>
<p>这里注意了。和之前我们讨论的backBarButtonItem归属哪个ViewController时候一样，我们这里的toolbarItems是归属于当前的ViewController。因此这里我们要在首页显示，我们就设置RootVC的toolbarItems属性。另外这个toolBar最终还是UINavigationController的<br>。因此其是否显示还是要通过这里的额navVC来控制。</p>
<h2 id="结语">结语</h2><p>通过Navigation我们可以构建一个基本的App框架，包括了界面之间的跳转，header/footer的设置以及动作的设置等。这里没有列举出所有的API以及切换的特效，也没有丰富的自定义。但是根据上面的逻辑框架，在结合自定义的动画和View，是很方便可以实现一个与众不同的但是又符合<br>这个框架结构的App的。</p>

      
    </div>
    
    <div class="article-info article-info-index">
      
      
	<div class="article-tag tagcloud">
		<ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/blog/tags/navigation/">navigation</a></li></ul>
	</div>

      
	<div class="article-category tagcloud">
	<a class="article-category-link" href="/blog/categories/iOS/">iOS</a>
	</div>


      
      <div class="clearfix"></div>
    </div>
    
  </div>
  
</article>







  
    <article id="post-swift/swift_继承中构造函数/继承中的构造函数" class="article article-type-post" itemscope itemprop="blogPost">
  
    <div class="article-meta">
      <a href="/blog/2015/04/04/swift/swift_继承中构造函数/继承中的构造函数/" class="article-date">
  	<time datetime="2015-04-03T16:00:00.000Z" itemprop="datePublished">2015-04-04</time>
</a>
    </div>
  
  <div class="article-inner">
    
      <input type="hidden" class="isFancy" />
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="/blog/2015/04/04/swift/swift_继承中构造函数/继承中的构造函数/">Swift语法：继承中的构造函数</a>
    </h1>
  

      </header>
      
    
    <div class="article-entry" itemprop="articleBody">
      
        <p>Swift要求在构造函数中要完成对所有“Stored”属性的初始化操作。因此在继承时，也要保证这一要求。</p>
<p>##一、Sotred Properties<br>什么是”Sotred Properties”?苦逼程序员在大一或者大n得时候学习C++或者Java时，不是只有“属性”？咋来了个“Stored”?</p>
<blockquote>
<p>在Swift里面，类的属性分成两种，一种叫做“Sotred Properties”，另一种叫做“Computed Properties”</p>
</blockquote>
<p>简单来说，“Stored Properties”就是大学里学C++、Java里面的属性。凡是可以存一个值的就叫她“stored”，那什么是“Computed”呢？苦逼程序员一般都听说过C#还有OC（Objective-C）,这两个语言中都有个get和set的语法糖，比如在OC中声明为”@property a”的成员，其实他有个类似这里“Stored”属性的“_a”成员，然后当使用“.a”访问时，其实类似于C++/Java里面的getA方法。在这个get方法中可以添加计算逻辑，比如double一下。是计算过之后的值，因此管他们叫做“Computed”</p>
<p>在Swift里面，前者的定义和一般语言中得属性定义没有什么差别，后者则是在变量后面用一个大括号包裹着一个get/set方法：</p>
<pre><code><span class="class"><span class="keyword">class</span> <span class="title">People</span> </span>{
    <span class="variable"><span class="keyword">var</span> name</span>: String
    <span class="variable"><span class="keyword">var</span> _age</span>: <span class="typename">Int</span>
    <span class="variable"><span class="keyword">var</span> age</span> : <span class="typename">Int</span> {
        <span class="keyword">set</span>(age) {
            <span class="keyword">if</span> (age &gt;<span class="number">0</span>) {
                _age = age
            }
        }

        <span class="keyword">get</span>() {
            <span class="keyword">return</span> _age
        }
    }
}
</code></pre><p>上述代码中<code>name</code>是一个“Stored”属性，而<code>age</code>则是一个“Computed”属性</p>
<h2 id="二、Designated_Initializers">二、Designated Initializers</h2><p>这个名字这么高大上，也不容易理解，其实就是一个意思:“通过自己或者父类的构造函数完成对所有Stored属性的初始化的构造函数”</p>
<p>就是要再构造函数里面将自己的成员都做初始化操作。这里要注意了，必须先初始化自己的然后才能用 <code>super.init(xxx)</code> 来调用父类的构造函数。而不同于我们在C++或者Java中优先初始化父类。</p>
<h2 id="三、Convenience_Initializers">三、Convenience Initializers</h2><p>有了上面的构造函数，为什么还有另一种分类呢？答案从名字中也可以看出来，就是要提供一个友好的构造接口，我们可以认为他是一系列的helper函数构造函数。按照Swift的说法，我们尽量减少 Designated的构造函数，而用Convenience构造函数提供接口。这里我们可以想象一下在Objective-C中，一个类通常有一个init()函数，然后还有一系列的init:withXXX的函数，前者可以认为是Designated的后者可以认为是Convenience的。</p>
<h2 id="四、Initial_Rules">四、Initial Rules</h2><p>了解了构造函数的分类，我们再来看下构造时的规则，这也是这篇文章的意义所在。</p>
<ul>
<li>一个Designated构造必须要调用一个其父类的Designated构造函数，没有父类的除外</li>
<li>一个Convenience构造函数必须调用该类的一个构造函数，可以是Designated也可以是另一个Convenience的构造函数</li>
<li>一个Convenience的调用路径上，最终必须调用一个Designated构造函数</li>
</ul>
<p><img src="http://images.libcz.com:8000/images/blog/swift/swift_继承中构造函数/init_chain.png" alt="init_chain"></p>
<p>如上图所示，最下面的子类的两个Designated的构造函数都调用了父类的Designated构造函数，而其Convenience构造函数则通过调用其Designated进行初始化，最上面的父类的第二个Convenience构造函数调用其第一个Convenience，最终还是调用了其Designated构造函数。</p>
<p>这样的规则是的Swift同OC以及Cocos2dx遵循同样的“两段式构造”规则。首先在构造函数里面保证所有的Sotred的属性都被初始化了，这里的初始化主要是默认初始化。然后进行第二步，用户再对这些值作自定义修改，从而对外表现为特定初始化。</p>
<p>为了满足这样的规则，我们在写构造函数就要注意了</p>
<ul>
<li>Designated构造函数必须先初始化好子类中所有的Stored的属性，才能调用父类的Designatede构造函数</li>
<li>Designated构造函数如果要修改继承父类中得属性的值，必须在调用了父类的Designated构造函数之后，否则回报父类覆盖</li>
<li>一个Convenience构造函数如果想修改属性的默认值，必须在调用了Designated构造函数之后，否则会被Designed构造函数覆盖</li>
<li>在完成对所有Stored属性的初始化之前，是不能引用实例方法和属性的，比如用self.x访问一个属性来初始化另一个属性。</li>
</ul>
<p>这里我们看一个表示两段构造的例子：<br><img src="http://images.libcz.com:8000/images/blog/swift/swift_继承中构造函数/two_step_init_one.png" alt="two_step_init_one"><br>首先子类从Convenience构造函数开始，先调用其Designated构造函数，在这初始化子类里面的Stored属性，然后调用父类的Designated构造函数，初始化好父类的Stored属性。这样完成第一步，此后才可以访问实例的属性。<br><img src="http://images.libcz.com:8000/images/blog/swift/swift_继承中构造函数/two_step_init_two.png" alt="two_step_init_two"><br>进入到第二阶段，从父类开始，执行用户的代码对初始化后的属性作修改，然后再到子类里面再做修改，这里可以修改继承的父类的属性，最后到Convenience构造函数里面可以访问实例的属性方式进行再自定义修改，比如将UIView的一个子类里面的某个属性设置为self.bouds大小。</p>
<p>##五、继承和重写构造函数</p>
<p>在Swift中，默认情况下，子类是不继承父类的构造函数的，需要子类自己选择是否调用父类的构造函数。调用父类的构造方法通过<code>super</code>来指定父类如<code>super.init()</code></p>
<p>与C++和Java不同，在Swift中子如果要重写父类的Designated构造函数，需要在函数前面添加overide关键字,而与父类的Convenience构造函数同名时则不用写overide。</p>
<p>另外，有两个极端情况：</p>
<ul>
<li>如果子类不提供Designated构造函数，那么默认继承了所有的父类的Designated构造函数</li>
<li>如果子类overide了父类的所有Designated构造函数，那么子类默认继承了父类的所有Convenience构造函数</li>
</ul>

      
    </div>
    
    <div class="article-info article-info-index">
      
      
	<div class="article-tag tagcloud">
		<ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/blog/tags/swift/">swift</a></li></ul>
	</div>

      
	<div class="article-category tagcloud">
	<a class="article-category-link" href="/blog/categories/swift/">swift</a>
	</div>


      
      <div class="clearfix"></div>
    </div>
    
  </div>
  
</article>







  
    <article id="post-golang/standard_library/flag/golang实现命令行菜单cli效果" class="article article-type-post" itemscope itemprop="blogPost">
  
    <div class="article-meta">
      <a href="/blog/2015/03/05/golang/standard_library/flag/golang实现命令行菜单cli效果/" class="article-date">
  	<time datetime="2015-03-04T16:00:00.000Z" itemprop="datePublished">2015-03-05</time>
</a>
    </div>
  
  <div class="article-inner">
    
      <input type="hidden" class="isFancy" />
    
    
      <header class="article-header">
        
  
    <h1 itemprop="name">
      <a class="article-title" href="/blog/2015/03/05/golang/standard_library/flag/golang实现命令行菜单cli效果/">Golang实现命令行菜单CLI效果</a>
    </h1>
  

      </header>
      
    
    <div class="article-entry" itemprop="articleBody">
      
        <p>在Unix-Like系统中，CLI(Command Line Interface)通常都是通过传统的getopt来实现的，在Python中除了getopt外还有更高级的optparse以及argparse。在Golang中，系统库flag为我们提供了CLI的支持，当然还有一些更高级的封装实现，如<a href="https://github.com/codegangsta/cli" target="_blank" rel="external">codegangsta/cli</a>,<a href="https://github.com/docker/docker/tree/master/pkg/mflag" target="_blank" rel="external">docker增强的flag</a>。但是对于平民百姓的一般使用，用官方的flag库即可。</p>
<p>##初试<br>使用Flat模块，通过几行代码就可以构建一个丰富的CLI界面了：</p>
<pre><code>package main

<span class="keyword">import</span> (
    <span class="string">"flag"</span>
    <span class="string">"fmt"</span>
)

<span class="func"><span class="keyword">func</span> <span class="title">main</span><span class="params">()</span></span> {

    flag.<span class="type">Usage</span> = <span class="func"><span class="keyword">func</span><span class="params">()</span></span> {
        fmt.<span class="type">Println</span>(<span class="string">"Usage:Test Flag Module"</span>)
        flag.<span class="type">PrintDefaults</span>()
    }

    <span class="keyword">var</span> logSwitch bool
    <span class="keyword">var</span> outputPath string

    flag.<span class="type">BoolVar</span>(&amp;logSwitch, <span class="string">"l"</span>, <span class="literal">false</span>, <span class="string">"    Logcat switch "</span>)
    flag.<span class="type">StringVar</span>(&amp;outputPath, <span class="string">"out"</span>,<span class="string">"./output"</span>,<span class="string">"     Path to output"</span>)
    <span class="keyword">var</span> v = flag.<span class="type">Bool</span>( <span class="string">"v"</span>, <span class="literal">true</span>, <span class="string">"    Show Version"</span>)

    flag.<span class="type">Parse</span>()

    fmt.<span class="type">Println</span>(<span class="string">"v is "</span>,*v)
    <span class="keyword">for</span> i,<span class="number">_</span>  := range flag.<span class="type">Args</span>() {
        fmt.<span class="type">Println</span>(<span class="string">"the "</span>,i,<span class="string">" th arg is:"</span>,flag.<span class="type">Arg</span>(i))
    }

}
</code></pre><p>执行 <code>go build</code> 并运行程序后，可以尝试几个选项，比如：</p>
<pre><code>./test_flag -h
Usage:Test Flag Module
     -<span class="ruby">l=<span class="symbol">false:</span> <span class="constant">Logcat</span> switch
</span>     -<span class="ruby">out=<span class="string">"./output"</span><span class="symbol">:</span> <span class="constant">Path</span> to output
</span>  -<span class="ruby">v=<span class="symbol">true:</span> <span class="constant">Show</span> <span class="constant">Version</span></span>
</code></pre><p>这里可以使用</p>
<ul>
<li>带有选项和值的参数，如： <code>./test_flag -l false</code> </li>
<li>带有两个横杠的，如： <code>./test_flag --out ./output_path</code></li>
<li>单个参数的选项，如：<code>./test_flag -v</code></li>
<li>带有多个参数，如：<code>./test_flag one two</code></li>
</ul>
<p>在上面的例子中，通过调用<code>flag.Parse()</code>对选项进行了解析，从而可以获得选项字段。而选项字段内容的获取则通过<br><code>Type[Var]()</code>的接口获得，其中参数忽略第一个分别是</p>
<ul>
<li>命令行上给到的名称</li>
<li>默认值</li>
<li>help提示信息</li>
</ul>
<p>主要提供了Bool,Duration,Float64,Int,UInt,Int64,UInt64,String几种类型数据的获得，每个类型有一个带有Var后缀的版本，该版本会再前面多<br>增加一个参数，为对应类型的指针，用来存储获得的值，而不带的版本则是返回一个该类型的指针，从而获得对应选项的值。如：</p>
<pre><code><span class="function">func <span class="title">Int</span>(<span class="params">name <span class="keyword">string</span>, <span class="keyword">value</span> <span class="keyword">int</span>, usage <span class="keyword">string</span></span>) *<span class="keyword">int</span>
func <span class="title">IntVar</span>(<span class="params">p *<span class="keyword">int</span>, name <span class="keyword">string</span>, <span class="keyword">value</span> <span class="keyword">int</span>, usage <span class="keyword">string</span></span>)</span>
</code></pre><p>分别是通过返回值和指定变量指针的方式。</p>
<p>在写Python的命令行时，有时候为了兼容多个Python版本，通常选择最裸的argv的方式，这样通常都免不了对参数进行转换的操作，如:</p>
<pre><code>try:
    count = <span class="function"><span class="title">int</span><span class="params">(sys.argv[<span class="number">1</span>])</span></span>
except:
    <span class="function"><span class="title">echo_helper</span><span class="params">()</span></span>
</code></pre><p>而上面的这些带有类型的接口就已经完成了这样的操作，比如传入一个浮点数给到一个Int<a href="">Var</a>的选项，将会自动打印出Help信息并进行退出动作。</p>
<p>上面我们看到通过为<code>flag.Usage</code> 进行赋值，可以实现自定义的help输出。如果使用了上面的demo可能会觉得奇怪，为什么没有对各个选项写help信息<br>为什么默认的help会打印出对应的信息。这个神奇的语法就得依赖于 <code>flag.PrintDefaults()</code>，他会把其他选项中的help一并打印出来。<br>另外在写单个项的help的时候，字符串最好tab一个键开头，这样<code>flag.PrintDefaults()</code>在合成help信息的时候，排版起来相对好看。</p>
<p>除了选项外，还可以获取没有选项带的参数值，根据上面的经验，这些值也是需要Parse之后才能得到，因此对其的遍历放在了Parse操作之后，否则<br>取出来的都是空。</p>
<p>上面的这个Demo基本可以作为一个模板，稍加修改便可以满足一个简单的CLI的需求。下面对Unix-Like命令中几种常见选项做一个实现。</p>
<p>##-v/–verion</p>
<p>对于单个选项的开关，需要将该选项定义为bool类型，并默认给一个false的值。这样可以实现当有该选项时，会被设置为true，否则任为false。</p>
<pre><code><span class="tag">var</span> v = flag.<span class="function"><span class="title">Bool</span><span class="params">( <span class="string">"v"</span>, false, <span class="string">"    Show Version"</span>)</span></span>

flag.<span class="function"><span class="title">Parse</span><span class="params">()</span></span>
fmt.<span class="function"><span class="title">Println</span><span class="params">(<span class="string">"v is "</span>,*v)</span></span>
</code></pre><p>这样在没有加 “-v”的时候得到的结果为false,加了的话，得到的是true。</p>
<p>flag比较讨厌的是，对于长短选项没有做特殊的合并方法。感觉只能二者选其一了。</p>
<p>##-o a.out</p>
<p>如果想获取一个带有参数的选项的值，可以选择的使用上面的Type<a href="">Var</a>系列的函数了，这里以String举例：</p>
<pre><code><span class="tag">var</span> outputName string
<span class="tag">var</span> outputDir = flag.<span class="function"><span class="title">String</span><span class="params">(<span class="string">"o"</span>,<span class="string">""</span>,<span class="string">"    output directory"</span>)</span></span>
flag.<span class="function"><span class="title">StringVar</span><span class="params">(&amp;outputName,<span class="string">"n"</span>,<span class="string">""</span>, <span class="string">"    output name"</span>)</span></span>
flag.<span class="function"><span class="title">Parse</span><span class="params">()</span></span>
fmt.<span class="function"><span class="title">Println</span><span class="params">(<span class="string">"Output directory is "</span>,*outputDir,<span class="string">" And name is "</span>,outputName)</span></span>
</code></pre><p>这里通过带有Var和不带的接口实现了获取输出目录和文件名的操作。</p>
<p>##mkdir tmp<br>如果不想使用选项，而直接带上参数，flag也是支持的，可以通过flag.Args()获得一个sting的list，或者通过<br>flag.Arg(index int)获得第几个参数。但是这里受限的时，参数只能获得string类型，具体需要自己转换一下，就和Python里面<br>使用getopt一样。<br>      flag.Parse()</p>
<pre><code><span class="keyword">if</span> len(flag.Args())  !=<span class="number">2</span> {
    flag.Usage()
    <span class="keyword">return</span>
}

argName := flag.Arg(0)
argAge := flag.Arg(1)
age,err := strconv.Atoi(argAge)
<span class="keyword">if</span> err != nil {
    flag.Usage()
    <span class="keyword">return</span>
}

fmt.Printf(<span class="string">"Name is %s,Age is %d\n"</span>,argName,age)
</code></pre><p>这里先对参数个数进行判断，然后再用strconv来实现对字符串的转换操作。如果转换不成功则退出。</p>
<p>##Help</p>
<p>上面已经对Help进行了比较详尽的说明了，总结就是在适当的时候会调用flag.Usage。其是一个无参数不返回值的函数，相当于<br>C里面的<code>void (* func)()</code>。其配合一个助手<code>flag.PrintDefaults()</code>可以将选项中得help信息也打印出来。基本就是一个<br>范式，每次这么写就对了：</p>
<pre><code>flag.Usage = <span class="function"><span class="keyword">func</span><span class="params">()</span> {</span>
    fmt.Println(<span class="string">"Usage:Test Flag Module"</span>)
    flag.PrintDefaults()
}
</code></pre>
      
    </div>
    
    <div class="article-info article-info-index">
      
      
	<div class="article-tag tagcloud">
		<ul class="article-tag-list"><li class="article-tag-list-item"><a class="article-tag-list-link" href="/blog/tags/golang-cli/">golang cli</a></li></ul>
	</div>

      
	<div class="article-category tagcloud">
	<a class="article-category-link" href="/blog/categories/golang/">golang</a>
	</div>


      
      <div class="clearfix"></div>
    </div>
    
  </div>
  
</article>







  
  
</div>
      <footer id="footer">
  <div class="outer">
    <div id="footer-info">
      <p><a rel="license" href="http://creativecommons.org/licenses/by-nd/4.0/"><img alt="知识共享许可协议" style="border-width:0" src="https://i.creativecommons.org/l/by-nd/4.0/88x31.png" /></a><br />本站采用<a rel="license" href="http://creativecommons.org/licenses/by-nd/4.0/">知识共享Attribution-NoDerivatives 4.0 国际许可协议</a>进行许可。</p>
    	<div class="footer-left">
    		&copy; 2015 C Z
    	</div>
      	<div class="footer-right">
      		<a href="http://hexo.io/" target="_blank">Hexo</a>  Theme <a href="https://github.com/litten/hexo-theme-yilia" target="_blank">Yilia</a> by Litten
      	</div>
    </div>
  </div>
</footer>

    </div>
    
  <link rel="stylesheet" href="/blog/fancybox/jquery.fancybox.css" type="text/css">


<script>
	var yiliaConfig = {
		fancybox: true,
		mathjax: true,
		animate: true,
		isHome: true,
		isPost: false,
		isArchive: false,
		isTag: false,
		isCategory: false,
		open_in_new: false
	}
</script>
<script src="http://7.url.cn/edu/jslib/comb/require-2.1.6,jquery-1.9.1.min.js" type="text/javascript"></script>
<script src="/blog/js/main.js" type="text/javascript"></script>






<script type="text/x-mathjax-config">
MathJax.Hub.Config({
    tex2jax: {
        inlineMath: [ ['$','$'], ["\\(","\\)"]  ],
        processEscapes: true,
        skipTags: ['script', 'noscript', 'style', 'textarea', 'pre', 'code']
    }
});

MathJax.Hub.Queue(function() {
    var all = MathJax.Hub.getAllJax(), i;
    for(i=0; i < all.length; i += 1) {
        all[i].SourceElement().parentNode.className += ' has-jax';                 
    }       
});
</script>

<script type="text/javascript" src="http://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
</script>


  </div>
</body>
</html>